//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V0.3.1
#include "flash_driver.h"
#include <string.h>

typedef struct
{
	uint8_t cmd;
	uint8_t addr_L_8bit;
	uint8_t addr_M_8bit;
	uint8_t addr_S_8bit;
	uint8_t buf[1];
}Flash_TRx_Buf_t;

static uint8_t Flash_TRx_Sum_Buf[FLASH_BUFF_SIZE + sizeof(Flash_TRx_Buf_t)];
static WHT_Flash_State_t WHT_Flash_State = { Flash_TRx_Idle , Flash_No_Error};

#define Flash_TRx_Buf    ((Flash_TRx_Buf_t*)&Flash_TRx_Sum_Buf)


/**********************驱动初始化配置*********************/
static SemaphoreHandle_t TRx_xSemaphore;//二值信号量句柄

static WHT_SPI_Cache_t wht_cache;
static volatile unsigned int* Flash_Soft_NSS;

static void WHT_TRx_Idle_IT_Callback(void);
static void WHT_FLASH_Driver_GPIO_Init(void)
{
	if (WHT_SPI_BUS1->Config.NSS == Soft_NSS)//配置片选引脚
	{
		WHT_GPIO_BSP.WHT_Set_Clock(FLASH_NSS_GPIO_PORT, ENABLE);
		WHT_GPIO_BSP.WHT_Set_State(FLASH_NSS_GPIO_PORT, FLASH_NSS_GPIO_PIN, Hig);
		WHT_GPIO_BSP.WHT_Set_Mode(FLASH_NSS_GPIO_PORT, FLASH_NSS_GPIO_PIN, Mode_Out_PP);
		WHT_GPIO_BSP.WHT_Config_Bit_Output(FLASH_NSS_GPIO_PORT, FLASH_NSS_GPIO_PIN, &Flash_Soft_NSS);
	}
}
static void WHT_Set_NSS_State_Callback(WHT_SPI_IO_State_enum state)
{
	*Flash_Soft_NSS = state;
}
static void WHT_FLASH_Driver_Init(void)
{
    if (WHT_SPI_BUS1_Init() != 0)
    {
        /* 总线初始化失败 */
        return;
    }
	WHT_FLASH_Driver_GPIO_Init();
	wht_cache.Set_NSS_State_CB = WHT_Set_NSS_State_Callback;
	wht_cache.TRx_Finish_IT_CB = WHT_TRx_Idle_IT_Callback;

    TRx_xSemaphore = xSemaphoreCreateBinary();
}
/**********************驱动初始化配置*********************/





/************************** start read & write ********************************/
/*空闲中断回调函数*/
static void WHT_TRx_Idle_IT_Callback(void)
{
    BaseType_t xHigherPriorityTaskWoken;

    xSemaphoreGiveFromISR(TRx_xSemaphore, &xHigherPriorityTaskWoken);//释放信号量
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
static void WHT_FLASH_Driver_Write_Cmd(uint8_t cmd)
{
	while (WHT_SPI_BUS1->Mutex == SPI_Lock)//等待互斥锁成功打开
		vTaskDelay(1);
	wht_cache.Dir = SPI_WO;
	wht_cache.Buffer_Count = 1;
	wht_cache.Tx_Buffer = &cmd;
	wht_cache.Rx_Buffer = NULL;

	WHT_SPI_BUS_OPS.Read_Write(WHT_SPI_BUS1, &wht_cache);
	if (WHT_SPI_BUS1->State != SPI_No_Error)
		WHT_Flash_State.Error_State = Flash_Error;
}
static void WHT_FLASH_Driver_Write_Data(uint8_t* const input_buf, uint32_t count)
{
	while (WHT_SPI_BUS1->Mutex == SPI_Lock)//等待互斥锁成功打开
		vTaskDelay(1);
	wht_cache.Dir = SPI_WO;
	wht_cache.Buffer_Count = count;
	wht_cache.Tx_Buffer = input_buf;
	wht_cache.Rx_Buffer = NULL;

	extern uint32_t SystemCoreClock;//out system_stm32f10x.c
	TickType_t Tick_Count = 0;
	switch (WHT_SPI_BUS1->Config.Clock_Div)
	{
	case APBx_DIV2:  Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide *   2 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV4:  Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide *   4 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV8:  Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide *   8 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV16: Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide *  16 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV32: Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide *  32 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV64: Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide *  64 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV128:Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide * 128 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV256:Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide * 256 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	}
	if (Tick_Count)
		WHT_SPI_BUS_OPS.Read_Write_DMA(WHT_SPI_BUS1, &wht_cache);
	else
		WHT_SPI_BUS_OPS.Read_Write(WHT_SPI_BUS1, &wht_cache);
	
    if (WHT_SPI_BUS1->Mutex == SPI_Unlock)//传输结束
    {
		if (WHT_SPI_BUS1->State != SPI_No_Error)
			WHT_Flash_State.Error_State = Flash_Error;
    }
    else
        xSemaphoreTake(TRx_xSemaphore, portMAX_DELAY);//等待信号量
}
static void WHT_FLASH_Driver_Read_Data(uint8_t* const input_buf,uint8_t* const output_buf, uint32_t count)
{
	while (WHT_SPI_BUS1->Mutex == SPI_Lock)//等待互斥锁成功打开
		vTaskDelay(1);
	wht_cache.Dir = SPI_RW;
	wht_cache.Buffer_Count = count;
	wht_cache.Tx_Buffer = input_buf;
	wht_cache.Rx_Buffer = output_buf;

	extern uint32_t SystemCoreClock;//out system_stm32f10x.c
	TickType_t Tick_Count = 0;
	switch (WHT_SPI_BUS1->Config.Clock_Div)
	{
	case APBx_DIV2:  Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide  *   2 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV4:  Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide  *   4 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV8:  Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide  *   8 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV16: Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide  *  16 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV32: Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide  *  32 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV64: Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide  *  64 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV128:Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide  * 128 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	case APBx_DIV256:Tick_Count = count * WHT_SPI_BUS1->Config.Bit_Wide  * 256 / (SystemCoreClock / 1000) / portTICK_RATE_MS; break;//单位ms/Tick;
	}
	if (Tick_Count)
		WHT_SPI_BUS_OPS.Read_Write_DMA(WHT_SPI_BUS1, &wht_cache);
	else
		WHT_SPI_BUS_OPS.Read_Write(WHT_SPI_BUS1, &wht_cache);

    if (WHT_SPI_BUS1->Mutex == SPI_Unlock)//传输结束
    {
		if (WHT_SPI_BUS1->State != SPI_No_Error)
			WHT_Flash_State.Error_State = Flash_Error;
    }
    else
        xSemaphoreTake(TRx_xSemaphore, portMAX_DELAY);//等待信号量
}
/************************** end read & write **********************************/

//读取flash忙碌状态
static FlagStatus WHT_FLASH_Driver_Waiting_Busy_State(void)
{
	/*先读取1次*/
	Flash_TRx_Buf->cmd = W25Q_Read_Status_Reg;
	WHT_FLASH_Driver_Read_Data((uint8_t*)Flash_TRx_Buf, (uint8_t*)Flash_TRx_Buf, 2);
	if ((((uint8_t*)Flash_TRx_Buf)[1] & 0x01) == 0x00)
		return RESET;
	/*按照用户指定时间读取*/
	vTaskDelay(Page_Program_Time / portTICK_RATE_MS + 1);
	Flash_TRx_Buf->cmd = W25Q_Read_Status_Reg;
	WHT_FLASH_Driver_Read_Data((uint8_t*)Flash_TRx_Buf, (uint8_t*)Flash_TRx_Buf, 2);
	return (((uint8_t*)Flash_TRx_Buf)[1] & 0x01) ? SET : RESET;
}
//开启写使能则可以擦除及写入数据
static void WHT_FLASH_Driver_Write_En(FunctionalState state)
{
	state == DISABLE ? WHT_FLASH_Driver_Write_Cmd(W25Q_Write_Disable) : WHT_FLASH_Driver_Write_Cmd(W25Q_Write_Enable);
}


//读取设备的ID
static uint32_t WHT_FLASH_Driver_Read_Jedec_ID(void)
{
	uint32_t JEDEC_ID = 0x00;
	Flash_TRx_Buf_t Temp_Buf = { 0 };

	WHT_Flash_State.Error_State = Flash_No_Error;
	WHT_Flash_State.Idle_State = Flash_TRx_Busy;//忙碌
	if (WHT_FLASH_Driver_Waiting_Busy_State() == SET)
		goto Game_Over;
	Temp_Buf.cmd = W25Q_Jedec_Device_ID;
	WHT_FLASH_Driver_Read_Data((uint8_t*)&Temp_Buf, (uint8_t*)&Temp_Buf, 4);
	JEDEC_ID |= ((uint8_t*)&Temp_Buf)[1] << 16;
	JEDEC_ID |= ((uint8_t*)&Temp_Buf)[2] << 8;
	JEDEC_ID |= ((uint8_t*)&Temp_Buf)[3] << 0;
Game_Over:
	WHT_Flash_State.Idle_State = Flash_TRx_Idle;//空闲
	return JEDEC_ID;
}
//擦除
static void WHT_FLASH_Driver_Erase(WHT_W25Q_Erase_Sel_enum erase_sel, uint32_t block_number, WHT_Sector_enum sector_number)
{
	uint32_t erase_time;
	uint32_t erase_addr;
	Flash_TRx_Buf_t Temp_Buf;

	WHT_Flash_State.Error_State = Flash_No_Error;
	WHT_Flash_State.Idle_State = Flash_TRx_Busy;//忙碌
	if (WHT_FLASH_Driver_Waiting_Busy_State() == SET)
		goto Game_Over;
	WHT_FLASH_Driver_Write_En(ENABLE);
	switch (erase_sel)
	{
	case Chip_Erase_All:
		WHT_FLASH_Driver_Write_Cmd(W25Q_Chip_Erase);
		erase_time = Chip_Erase_Time;
		break;
	case Sector_Erase_4KB:
		erase_addr = block_number * (flash_block_size_byte >> 0) + sector_number;
		Temp_Buf.cmd =W25Q_Sector_Erase;
		Temp_Buf.addr_L_8bit = (erase_addr >> 16) & 0xff;
		Temp_Buf.addr_M_8bit = (erase_addr >>  8) & 0xff;
		Temp_Buf.addr_S_8bit = (erase_addr >>  0) & 0xff;
		WHT_FLASH_Driver_Write_Data((uint8_t*) & Temp_Buf, 4);
		erase_time = Sector_Erase_Time_4KB;
		break;
	case Block_Erase_32KB:
		erase_addr = block_number * (flash_block_size_byte >> 2);
		Temp_Buf.cmd =W25Q_Block_Erase_32;
		Temp_Buf.addr_L_8bit = (erase_addr >> 16) & 0xff;
		Temp_Buf.addr_M_8bit = (erase_addr >>  8) & 0xff;
		Temp_Buf.addr_S_8bit = (erase_addr >>  0) & 0xff;
		WHT_FLASH_Driver_Write_Data((uint8_t*)&Temp_Buf, 4);
		erase_time = Block_Erase_Time_32KB;
	case Block_Erase_64KB:
		erase_addr = block_number * (flash_block_size_byte >> 0);
		Temp_Buf.cmd =W25Q_Block_Erase_64;
		Temp_Buf.addr_L_8bit = (erase_addr >> 16) & 0xff;
		Temp_Buf.addr_M_8bit = (erase_addr >>  8) & 0xff;
		Temp_Buf.addr_S_8bit = (erase_addr >>  0) & 0xff;
		WHT_FLASH_Driver_Write_Data((uint8_t*)&Temp_Buf, 4);
		erase_time = Block_Erase_Time_64KB;
		break;
	default:
		WHT_Flash_State.Error_State = Flash_Error;
		erase_time = 0;
		break;
	}

	do
	{
		vTaskDelay(10 / portTICK_RATE_MS);
		if (WHT_FLASH_Driver_Waiting_Busy_State() == RESET)
			break;
		if (erase_time < 10)
		{
			WHT_Flash_State.Error_State = Flash_Error;
			break;
		}
		else
			erase_time -= 10;
	} while (1);
Game_Over:
	WHT_Flash_State.Idle_State = Flash_TRx_Idle;//空闲
}
//随机地址读取
static void WHT_FLASH_Driver_Read(uint32_t read_addr, uint32_t count)
{
	WHT_Flash_State.Error_State = Flash_No_Error;
	WHT_Flash_State.Idle_State = Flash_TRx_Busy;//忙碌
	if (WHT_FLASH_Driver_Waiting_Busy_State() == SET)
		goto Game_Over;
	Flash_TRx_Buf->cmd = W25Q_Read_Data;
	Flash_TRx_Buf->addr_L_8bit = (read_addr >> 16) & 0xff;
	Flash_TRx_Buf->addr_M_8bit = (read_addr >>  8) & 0xff;
	Flash_TRx_Buf->addr_S_8bit = (read_addr >>  0) & 0xff;
	WHT_FLASH_Driver_Read_Data((uint8_t*)Flash_TRx_Buf, (uint8_t*)Flash_TRx_Buf, count + 4);
Game_Over:
	WHT_Flash_State.Idle_State = Flash_TRx_Idle;//空闲
}
//页写,count <= flash_page_size_byte
static void WHT_FLASH_Driver_Write_Page(uint32_t page_number, uint32_t count)
{
	uint32_t write_addr;

	if ((count > flash_page_size_byte) || (page_number > flash_page_size))
		return;
	WHT_Flash_State.Error_State = Flash_No_Error;
	WHT_Flash_State.Idle_State = Flash_TRx_Busy;//忙碌
	if (WHT_FLASH_Driver_Waiting_Busy_State() == SET)
		goto Game_Over;
	WHT_FLASH_Driver_Write_En(ENABLE);
	Flash_TRx_Buf->cmd = W25Q_Page_Program;
	write_addr = page_number * flash_page_size_byte;
	Flash_TRx_Buf->addr_L_8bit = (write_addr >> 16) & 0xff;//地址的高8位
	Flash_TRx_Buf->addr_M_8bit = (write_addr >>  8) & 0xff;//地址的中8位
	Flash_TRx_Buf->addr_S_8bit = (write_addr >>  0) & 0xff;//地址的低8位
	WHT_FLASH_Driver_Write_Data((uint8_t*)Flash_TRx_Buf, count + 4);
Game_Over:
	WHT_Flash_State.Idle_State = Flash_TRx_Idle;//空闲
}


//指定地址开始写入数据
static uint8_t Temp_Buf[flash_page_size_byte + sizeof(Flash_TRx_Buf_t)];
static void WHT_FLASH_Driver_Addr_Write_Page(uint32_t write_addr, uint8_t* datax, uint32_t count)
{
	static FlagStatus Func_Mutex = RESET;
	Flash_TRx_Buf_t* TRx_Buff = NULL;

	if (count > flash_page_size_byte)
		return;
	while (Func_Mutex == SET);
	Func_Mutex = SET;
	TRx_Buff = (Flash_TRx_Buf_t*)Temp_Buf;
	memcpy(TRx_Buff->buf, datax, count);
	if (WHT_FLASH_Driver_Waiting_Busy_State() == SET)
		return;
	WHT_FLASH_Driver_Write_En(ENABLE);
	TRx_Buff->cmd = W25Q_Page_Program;
	TRx_Buff->addr_L_8bit = (write_addr >> 16) & 0xff;//地址的高8位
	TRx_Buff->addr_M_8bit = (write_addr >>  8) & 0xff;//地址的中8位
	TRx_Buff->addr_S_8bit = (write_addr >>  0) & 0xff;//地址的低8位
	WHT_FLASH_Driver_Write_Data(Temp_Buf, count + 4);
	Func_Mutex = RESET;
}
//随机地址写
static void WHT_FLASH_Driver_Write(uint32_t data_addr, uint32_t count)
{
	uint32_t start_count;//首数据
	uint32_t page_count;//页数据
	uint32_t stop_count;//尾数据
	uint8_t* datax = Flash_TRx_Buf->buf;

	if ((data_addr + count) > flash_addr_size)//超出flash大小
		return;
	WHT_Flash_State.Error_State = Flash_No_Error;
	WHT_Flash_State.Idle_State = Flash_TRx_Busy;//忙碌
	start_count = flash_page_size_byte - data_addr % flash_page_size_byte;//首页写入个数
	if (count > start_count)
	{
		count -= start_count;
		page_count = count / flash_page_size_byte;//满页写入的个数
		stop_count = count % flash_page_size_byte;//尾页写入的个数
	}
	else
	{
		start_count = 0;   //首页写入的个数
		page_count = 0;	   //满页写入的个数
		stop_count = count;//尾页写入的个数
	}
	//开始对地址写入数据
	if (start_count)//首页写入个数
	{
		WHT_FLASH_Driver_Addr_Write_Page(data_addr, datax, start_count);
		if (WHT_Flash_State.Error_State != Flash_No_Error)
			goto Game_Over;	
		data_addr += start_count;
		datax += start_count;
	}
	for (; page_count > 0; page_count--)
	{
		WHT_FLASH_Driver_Addr_Write_Page(data_addr, datax, flash_page_size_byte);//写入页
		if (WHT_Flash_State.Error_State != Flash_No_Error)
			goto Game_Over;	
		data_addr += flash_page_size_byte;
		datax += flash_page_size_byte;
	}
	if (stop_count)//尾页写入个数
	{
		WHT_FLASH_Driver_Addr_Write_Page(data_addr, datax, stop_count);
		if (WHT_Flash_State.Error_State != Flash_No_Error)
			goto Game_Over;	
	}
Game_Over:
	WHT_Flash_State.Idle_State = Flash_TRx_Idle;//空闲
}
//扇区写
static void WHT_FLASH_Driver_Write_Sector(uint32_t block_number, WHT_Sector_enum sector_number)
{
	uint32_t write_addr;
	uint32_t i;
	uint8_t* datax = Flash_TRx_Buf->buf;

	if (block_number > flash_block_size)
		return;
	WHT_Flash_State.Error_State = Flash_No_Error;
	WHT_Flash_State.Idle_State = Flash_TRx_Busy;//忙碌
	write_addr = block_number * flash_block_size_byte + sector_number * flash_sector_size_byte;
	for (i = 0; i < flash_sector_size; i++)
	{
		WHT_FLASH_Driver_Addr_Write_Page(write_addr, datax, flash_page_size_byte);
		if (WHT_Flash_State.Error_State != Flash_No_Error)
			break;
		write_addr += flash_page_size_byte;
		datax += flash_page_size_byte;
	}
	WHT_Flash_State.Idle_State = Flash_TRx_Idle;//空闲
}



const WHT_Flash_Driver_t WHT_Flash_Driver =
{
	.WHT_Flash_State   = &WHT_Flash_State,
	.WHT_TRx_Buffer    = Flash_TRx_Buf->buf,
	.WHT_Init          = WHT_FLASH_Driver_Init,
	.WHT_Read_JEDEC_ID = WHT_FLASH_Driver_Read_Jedec_ID,
	.WHT_Erase         = WHT_FLASH_Driver_Erase,
	.WHT_Read_Data     = WHT_FLASH_Driver_Read,
	.WHT_Write_Data    = WHT_FLASH_Driver_Write,
	.WHT_Write_Page    = WHT_FLASH_Driver_Write_Page,
	#if (FLASH_BUFF_SIZE >= flash_sector_size_byte)
		.WHT_Write_Sector  = WHT_FLASH_Driver_Write_Sector,
	#endif
};
